﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using Yuecai.Data;

namespace Yuecai.Storage
{
    /// <summary>
    /// 数据存储管理的实现
    /// </summary>
    public class XmlStorage
    {
        //存储数据的XML文档
        private static XmlDocument _xml;
        //需要使用的随机数发生器
        private static Random _rd;
        //配置文件路径
        private static string _path;
        //密钥
        private static string _key;

        /// <summary>
        /// 初始化
        /// </summary>
        public static bool Init(string path, string key)
        {
            _path = path;
            _key = key;
            _xml = new XmlDocument();
            _xml.LoadXml(FileStorage.Read(path, key));
            _rd = new Random();
            return true;
        }

        /// <summary>
        /// 获取所有数据
        /// </summary>
        /// <param name="important">是否为重要数据</param>
        /// <returns>所有数据</returns>
        public static List<Item> GetItems(bool important)
        {
            return (from XmlElement e
                        in _xml.GetElementsByTagName(important ? "important" : "ordinary")[0].ChildNodes
                    select new Item
                               {
                                   AccountType = e.Attributes["accounttype"].Value,
                                   ID = e.Attributes["id"].Value,
                                   Password = e.Attributes["password"].Value,
                                   Remarks = e.Attributes["remarks"].Value,
                                   Sequence = _rd.Next(),
                                   UserName = e.Attributes["username"].Value
                               }).ToList();
        }

        /// <summary>
        /// 获取垃圾箱中的所有数据
        /// </summary>
        /// <returns>垃圾箱中的所有数据</returns>
        public static List<Tuple<Item, bool>> GetItemsInDustbin()
        {
            return (from XmlElement e in _xml.GetElementsByTagName("dustbin")[0].ChildNodes
                    select new Tuple<Item, bool>(
                        new Item
                            {
                                AccountType = e.Attributes["accounttype"].Value,
                                ID = e.Attributes["id"].Value,
                                Password = e.Attributes["password"].Value,
                                Remarks = e.Attributes["remarks"].Value,
                                Sequence = _rd.Next(),
                                UserName = e.Attributes["username"].Value
                            },
                        bool.Parse(e.Attributes["important"].Value))).ToList();
        }

        /// <summary>
        /// 删除数据到垃圾箱
        /// </summary>
        /// <param name="items">要删除的数据</param>
        /// <returns>是否成功</returns>
        public static bool DeleteItems(List<Tuple<Item, bool>> items)
        {
            var data = GetItems(items[0].Item2);
            data.RemoveAll(d => items.Any(i => i.Item1.ID == d.ID));
            _xml.GetElementsByTagName(items[0].Item2 ? "important" : "ordinary")[0].RemoveAll();
            AddItems(data, items[0].Item2);

            AddToDustbin(items);

            FileStorage.Write(_xml.InnerXml, _path, _key);
            return true;
        }

        /// <summary>
        /// 删除垃圾箱中的数据
        /// </summary>
        /// <param name="items">要删除的数据</param>
        /// <returns>是否成功</returns>
        public static bool DeleteItemsFromDustbin(List<Tuple<Item, bool>> items)
        {
            var data = GetItemsInDustbin();
            data.RemoveAll(d => items.Any(i => i.Item1.ID == d.Item1.ID));
            _xml.GetElementsByTagName("dustbin")[0].RemoveAll();
            AddToDustbin(data);

            FileStorage.Write(_xml.InnerXml, _path, _key);
            return true;
        }

        /// <summary>
        /// 还原垃圾箱中的数据
        /// </summary>
        /// <param name="items">要还原的数据</param>
        /// <returns>是否成功</returns>
        public static bool RestoreItems(List<Tuple<Item, bool>> items)
        {
            DeleteItemsFromDustbin(items);

            var o = new List<Item>();
            var i = new List<Item>();
            foreach (var tuple in items)
            {
                if(tuple.Item2)
                {
                    i.Add(tuple.Item1);
                }
                else
                {
                    o.Add(tuple.Item1);
                }
            }

            AddItems(o, false);
            AddItems(i, true);
            return true;
        }

        /// <summary>
        /// 直接永久删除数据
        /// </summary>
        /// <param name="items">要删除的数据</param>
        /// <param name="important">是否为重要数据</param>
        /// <returns>是否成功</returns>
        public static bool DeleteItemsDirectly(List<Item> items, bool important)
        {
            var data = GetItems(important);
            data.RemoveAll(d => items.Any(i => i.ID == d.ID));
            _xml.GetElementsByTagName(important ? "important" : "ordinary")[0].RemoveAll();
            AddItems(data, important);

            FileStorage.Write(_xml.InnerXml, _path, _key);
            return true;
        }

        /// <summary>
        /// 添加数据
        /// </summary>
        /// <param name="items">要添加的数据</param>
        /// <param name="important">是否为重要数据</param>
        /// <returns>是否成功</returns>
        public static bool AddItems(List<Item> items, bool important)
        {
            var data = GetItems(important);
            data.AddRange(items); 
            foreach (var item in data)
            {
                item.Sequence = _rd.Next();
            }
            data.OrderBy(d => d.Sequence);

            var f = _xml.GetElementsByTagName(important ? "important" : "ordinary")[0];
            f.RemoveAll();
            foreach (var item in data)
            {
                var e = _xml.CreateElement(important ? "iitem" : "oitem");
                e.SetAttribute("accounttype", item.AccountType);
                e.SetAttribute("id", item.ID);
                e.SetAttribute("password", item.Password);
                e.SetAttribute("remarks", item.Remarks);
                e.SetAttribute("username", item.UserName);

                f.AppendChild(e);
            }

            FileStorage.Write(_xml.InnerXml, _path, _key);
            return true;
        }

        /// <summary>
        /// 更改数据
        /// </summary>
        /// <param name="items">更改后的数据</param>
        /// <param name="important">是否为重要数据</param>
        /// <returns>是否成功</returns>
        public static bool UpdateItems(List<Item> items, bool important)
        {
            DeleteItemsDirectly(items, important);
            AddItems(items, important);
            return true;
        }

        /// <summary>
        /// 获取所有的账户类型
        /// </summary>
        /// <returns>所有账户类型</returns>
        public static List<String> GetAllTypes()
        {
            return (from XmlElement e in _xml.GetElementsByTagName("types")[0].ChildNodes
                    select e.Attributes["name"].Value).ToList();
        }

        /// <summary>
        /// 添加账户类型
        /// </summary>
        /// <param name="types">要添加的账户类型</param>
        /// <returns>是否成功</returns>
        public static bool AddTypes(List<String> types)
        {
            var data = GetAllTypes();
            data.AddRange(types);
            var f = _xml.GetElementsByTagName("types")[0];
            f.RemoveAll();
            foreach (var d in data)
            {
                var e = _xml.CreateElement("titem");
                e.SetAttribute("name", d);

                f.AppendChild(e);
            }

            FileStorage.Write(_xml.InnerXml, _path, _key);
            return true;
        }

        /// <summary>
        /// 删除账户类型
        /// </summary>
        /// <param name="types">要删除的账户类型</param>
        /// <returns>是否成功</returns>
        public static bool RemoveTypes(List<String> types)
        {
            var data = GetAllTypes();
            data.RemoveAll(d => types.Any(t => t == d));
            var f = _xml.GetElementsByTagName("types")[0];
            f.RemoveAll();
            foreach (var d in data)
            {
                var e = _xml.CreateElement("titem");
                e.SetAttribute("name", d);

                f.AppendChild(e);
            }

            FileStorage.Write(_xml.InnerXml, _path, _key);
            return true;
        }

        /// <summary>
        /// 获取矩阵路径或者矩阵原码
        /// </summary>
        /// <param name="tag">路径或者原码</param>
        /// <returns>需要的值</returns>
        public static String GetData(string tag)
        {
            return _xml.GetElementsByTagName(tag)[0].InnerXml;
        }

        /// <summary>
        /// 获取矩阵路径或者矩阵原码
        /// </summary>
        /// <param name="tag">路径或者原码</param>
        /// <param name="data">新的值</param>
        /// <returns>是否成功</returns>
        public static bool SetData(string tag, string data)
        {
            _xml.GetElementsByTagName(tag)[0].InnerXml = data;
            FileStorage.Write(_xml.InnerXml, _path, _key);
            return true;
        }

        //向垃圾箱中添加数据
        private static void AddToDustbin(IEnumerable<Tuple<Item, bool>> items)
        {
            var dustbin = GetItemsInDustbin();
            dustbin.AddRange(items);
            foreach (var item in dustbin)
            {
                item.Item1.Sequence = _rd.Next();
            }
            dustbin.OrderBy(d => d.Item1.Sequence);

            var fd = _xml.GetElementsByTagName("dustbin")[0];
            fd.RemoveAll();
            foreach (var item in dustbin)
            {
                var e = _xml.CreateElement("ditem");
                e.SetAttribute("accounttype", item.Item1.AccountType);
                e.SetAttribute("id", item.Item1.ID);
                e.SetAttribute("password", item.Item1.Password);
                e.SetAttribute("remarks", item.Item1.Remarks);
                e.SetAttribute("username", item.Item1.UserName);
                e.SetAttribute("important", item.Item2.ToString());

                fd.AppendChild(e);
            }
        }
    }
}
